package cl.ccs.migracionbcmc.util;


import cl.ccs.migracionbcmc.validators.exception.ValidatorException;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Clase Rut
 * @lastmodification 28 may 2013
 *
 */
public final class Rut {

    private static final String HYPHEN = "\u002d";
    private static final String RUT_WITHOUT_HYPHEN_PATTERN = "^[0-9]+[kK]?$";
    private static final String RUT_WITH_HYPHEN_PATTERN = "^[0-9]+\u002d[0-9kK]{1}$";
    private static final String OTHER_HYPHEN_PATTERN = "[\u2212\u2010\u2011\u2012\u2013\u2014\u2015]";
    private static final String FIRST_ZERO_PATTERN = "^0+";
    private static final String ZERO = "0";
    private static final String EMPTY = "";
    private static final char[] charactersDictionary = { '#', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'K', '0' };

    private String onlyRut;
    private String checkCharacter;

    public Rut(String rut) throws ValidatorException {
        setRut(rut);
    }

    /*
     * The minimal rut have a length of 2. Format: 19 or 1-9
     */

    private boolean isValidFormat(String rut) {
        boolean analysis = (haveFormat(rut, RUT_WITH_HYPHEN_PATTERN) || haveFormat(rut, RUT_WITHOUT_HYPHEN_PATTERN));
        return analysis;
    }

    private void setRut(String testingRut) throws ValidatorException {
        if (null != testingRut) {
            String rut = testingRut.replaceAll(OTHER_HYPHEN_PATTERN, HYPHEN); /* Convert dash(es) to default dash */
            if (isValidFormat(rut)) {
                String textRut = getTextRut(rut);
                String supposedCheck = getSupposedCheck(rut);
                String computedCheck = computeCheckCharacter(textRut);
                if (computedCheck.equals(supposedCheck)) {
                    setOnlyRut(textRut);
                    setCheckCharacter(computedCheck);
                } else {
                    throw new ValidatorException(Messages.INVALID_RUT_CHECK);
                }
            } else {
                throw new ValidatorException(Messages.INVALID_RUT);
            }
        } else {
            throw new ValidatorException(Messages.INVALID_RUT);
        }
    }

    private String getTextRut(String rut) {
        String textRut;
        int index = rut.lastIndexOf(HYPHEN);
        if (-1 == index) {
            index = rut.length() - 1;
        }
        textRut = rut.substring(0, index);
        textRut = textRut.replaceFirst(FIRST_ZERO_PATTERN, EMPTY);
        if (textRut.isEmpty()) {
            textRut = ZERO;
        }
        return textRut;
    }

    private String getSupposedCheck(String rut) {
        String supposedCheck;
        int index = rut.lastIndexOf(HYPHEN);
        if (-1 == index) {
            index = rut.length() - 1;
        } else {
            index++;
        }
        supposedCheck = rut.substring(index);
        supposedCheck = supposedCheck.replace('k', 'K');
        return supposedCheck;
    }

    private boolean haveFormat(String text, String regularExpression) {
        if (null == text) {
            return false;
        }
        Pattern pattern = Pattern.compile(regularExpression);
        Matcher matcher = pattern.matcher(text);
        return matcher.matches();
    }

    private String computeCheckCharacter(String rutText) {
        int counter = 2;
        int computation = 0;
        for (int i = rutText.length() - 1; i >= 0; i--) {
            counter = counter > 7 ? 2 : counter;
            computation += Integer.parseInt(rutText.substring(i, i + 1)) * counter++;
        }
        computation = (11 - (computation % 11));
        return String.valueOf(charactersDictionary[computation]);
    }

    @Override
    public String toString() {
        return getFullRut();
    }

    private void setOnlyRut(String onlyRut) {
        this.onlyRut = onlyRut;
    }

    private void setCheckCharacter(String checkCharacter) {
        this.checkCharacter = checkCharacter;
    }

    public String getFullRut() {
        String fullRut = (onlyRut + HYPHEN + checkCharacter);
        return fullRut;
    }

    public String getOnlyRut() {
        return onlyRut;
    }

    public String getCheckCharacter() {
        return checkCharacter;
    }

}
